package com.hq.common.cacha;

import java.io.Serializable;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.ibatis.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import com.hq.common.util.SpringBeanFactoryUtils;

/*
 * 使用第三方缓存服务器，处理二级缓存
 */
public class RedisCache implements Cache {

	private static final Logger logger = LoggerFactory.getLogger(RedisCache.class);

    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true);

    private final String COMMON_CACHE_KEY = "com.hq:MYBATIS:";
    
    private String id;

    private JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer();
    /**所有key*/
    private String getKeys() {
        return COMMON_CACHE_KEY + this.id + ":*";
    }
    /**
     * 按照一定规则标识key
     */
    private String getKey(Object key) {
    	System.out.println(key);
        return COMMON_CACHE_KEY + this.id + ":"+DigestUtils.md5Hex(String.valueOf(key));
    }
    
    @SuppressWarnings("unchecked")
	public RedisTemplate<String, Serializable> getRedisTemplate(){
        return (RedisTemplate<String, Serializable>) SpringBeanFactoryUtils.getBean("redisTemplate");
    }
    
    public RedisCache(final String id) {
        if (id == null) {
            throw new IllegalArgumentException("必须传入ID");
        }
        logger.debug("MybatisRedisCache:id=" + id);
        this.id = id;
    }

    @Override
    public String getId() {
        return this.id;
    }

    @Override
    public void putObject(Object key, Object value) {
    	logger.info("把数据放进redis:key:"+key.toString());
        if (getRedisTemplate()==null){
            return ;
        }
        if (value != null) {
            getRedisTemplate().opsForValue().set(getKey(key),jdkSerializer.serialize(value), 2, TimeUnit.DAYS);
        }
    }

    @Override
    public Object getObject(Object key) {
        if (getRedisTemplate()==null){
            return null;
        }
        try {
            if (key != null) {
                Object obj = getRedisTemplate().opsForValue().get(getKey(key));
                return jdkSerializer.deserialize((byte[]) obj);
            }
        } catch (Exception e) {
            logger.error("redis ");
        }
        return null;
    }

    @Override
    public Object removeObject(Object key) {
        if (getRedisTemplate()==null){
            return null;
        }
        try {
            if (key != null) {
                getRedisTemplate().delete(getKey(key));
                logger.debug("从缓存中移除-----"+this.id);
            }
        } catch (Exception e) {
        }
        return null;
    }

    @Override
    public void clear() {
        if (getRedisTemplate()==null){
            return ;
        }
        try {
            Set<String> keys = getRedisTemplate().keys(getKeys());
            getRedisTemplate().delete(keys);
            logger.debug("出现新增、修改、删除操作，清空对应Mapper缓存======>"+keys.size());
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }

    @Override
    public int getSize() {
        if (getRedisTemplate()==null){
            return 0;
        }
        Long size = getRedisTemplate().execute(
                new RedisCallback<Long>() {
                    @Override
                    public Long doInRedis(RedisConnection connection)
                            throws DataAccessException {
                        return connection.dbSize();
                    }
                });
        return size.intValue();
    }

    @Override
    public ReadWriteLock getReadWriteLock() {
        return this.readWriteLock;
    }

}